package cn.mujiankeji.mbrowser.功能.广告拦截
import 操作.工具类.left
import java.util.regex.Pattern

/**
 *
 * by Jen. 2020.10.
 */
object Adblock规则解析操作 {

    // 尽可能去获取特征词，1 IP > 2 域名/文件名 > 3 端口(:xxxx) >  4 段落(节) > 5 子域名 （双管线或单管线或http://xxx. xxx ） > 左斜线后5个连续值
    const val IP = 10
    const val YUMING = 11
    const val DUANKOU = 12
    const val JIE = 13
    const val ZUOXIEXIAN = 14
    const val YOUXIEXIAN = 15

    // 起始值判定 word = 第一个小数点前的值  无序，会重复
    const val HTTPX = 21 // 双管线 、 http* 、 |http*://  开始
    const val HTTPS = 22 // |https  https  开始
    const val HTTP = 23 // |http http 开始

    // 1. 获取类型IP的值
    fun getIp(text : String) : String?{

        val r = "(^|\\.|/|\\|\\|)((\\d{1,3}\\.){3}\\d{1,3})(\$|/|\\^|:)"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        if (matcher.find()){
            return matcher.group(2)
        }

        return null
    }
    fun getIps(text : String) : MutableList<String>{
        val r = "(^|\\.|/|\\|\\|)((\\d{1,3}\\.){3}\\d{1,3})(\$|/|\\^|:)"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        val ls = ArrayList<String>()
        while (matcher.find()){
            val v = matcher.group(2)
            if (v!=null) ls.add(v)
        }

        return ls
    }
    fun getIpKey(ip : String) : Long{
        val v = StringBuilder()

        val ks = ip.split(".")


        // 0 类型
        v.append(IP)

        // 1. 第1节 1
        v.append(getWordSign(ks[0].substring(0,1)))

        // 2 第2节 1
        v.append(getWordSign(ks[1].substring(0,1)))

        // 2 第3节 1
        v.append(getWordSign(ks[2].substring(0,1)))

        // 4 第4节 1
        v.append(getWordSign(ks[3].substring(0,1)))

        // 5 第1节 -1
        v.append(getWordSign(ks[0].substring(ks[0].length - 1,ks[0].length)))

        // 6 第2节 -1
        v.append(getWordSign(ks[1].substring(ks[1].length - 1,ks[1].length)))

        // 7 第3节 -1
        v.append(getWordSign(ks[2].substring(ks[2].length - 1,ks[2].length)))

        return v.toString().toLong()
    }

    // 2. 获取类似域名的值，比如域名或文件名，com.cn.  name.js
    fun getYuMing(text: String) : String?{
        val r = "(^|\\.|/|\\|\\|)([a-zA-Z-0-9]+(\\.(com|cn|org))?\\.[a-z]+)(\$|/|\\^|:|%)" //
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        if (matcher.find()){
            return matcher.group(2)
        }

        return null
    }
    fun getYuMings(text : String) : MutableList<String>{

        // adb.info/ad.js  以下正则就获取不到 ad.js ， 头尾判断不能取消，否则会 www.abc.com 只 获取 www.abc ！！！
        val sp = text.split("/")
        val ls = ArrayList<String>()

        for (s in sp) {
            if (!s.contains(".")) continue
            val r = "(^|\\.|/|\\|\\|)([a-zA-Z-0-9]+(\\.(com|cn|org))?\\.[a-z]+)(\$|/|\\^|:|%)" // ($|/|\^|:|%)
            val matcher = Pattern
                .compile(r,Pattern.CASE_INSENSITIVE)
                .matcher(s)


            while (matcher.find()){
                val v = matcher.group(2)
                if (v!=null) ls.add(v)
            }
        }



        return ls
    }
    fun getYuMingKey(domain : String) : Long{
        val v =StringBuilder()
        val ks = domain.split(".")

        // 0 类型
        v.append(YUMING)

        // 1. 00一级域名 xx.xx  ， 01二级域名 xx.xx.xx
        if (ks.size == 2) v.append("00")
        else v.append("01")

        // 2 第一段长度
        v.append(getLengthSign(ks[0]))

        // 3 第二段长度 没有则取第一段
        if (ks.size > 1) v.append(getLengthSign(ks[1]))
        else v.append(getLengthSign(ks[0]))

        // 4 第一段正1
        v.append(getWordSign(ks[0].substring(0,1)))

        // 5 第一段中间
        val mid = ks[0].length / 2
        v.append(getWordSign(ks[0].substring(mid,mid+1)))

        // 6 第一段倒1
        v.append(getWordSign(ks[0].substring(ks[0].length - 1,ks[0].length)))


        // 7 第二段倒1
        if (ks.size > 1) v.append(getWordSign(ks[1].substring(ks[1].length - 1,ks[1].length)))
        else v.append(getLengthSign(ks[0]))

        return v.toString().toLong()
    }

    // 3 端口 :000
    fun getDuanKou(text : String) : String? {
        val r = ":(\\d{2,5})(\$|/|^|:)"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        if (matcher.find()){
            return matcher.group(1)
        }

        return null
    }
    fun getDuanKous(text : String) : MutableList<String>{
        val r = ":(\\d{2,5})(\$|/|^|:)"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        val ls = ArrayList<String>()
        while (matcher.find()){
            val v = matcher.group(1)
            if (v!=null) ls.add(v)
        }

        return ls
    }
    fun getDuanKouKey(text : String) : String{
        var vs = DUANKOU.toString()
        vs += getTextKey(text)
        return vs
    }

    // 4 特殊字符包含的短节，?xxx= _mp4_
    fun getJie(rule : String) : String?{
        val ls  = getJieList(rule)
        if (ls.size == 0) return null
        var v = ls[0]
        for (l in ls) {
            if (l.length > v.length) v = l
        }
        return  v
    }
    fun getJieList(rule : String) : MutableList<String>{
        val list : MutableList<String> = ArrayList()
        val dt = arrayOf("?","=","!","/","_","&","(")

        for (startValue in dt) {
            var lt = rule.indexOf(startValue)
            while (lt != -1){
                var rt = lt+1

                while (rt < rule.length){
                    val k = rule.substring(rt,rt+1)
                    var pp = false // 匹配
                    for (s in dt) {
                        if (k == s) {
                            // 内容长度不超过2则继续
                            pp = rt - lt > 2

                            // 连续两个开始符号，则取后面一个
                            if (!pp && k == startValue && rt - lt == 1) pp = true
                            break
                        }
                    }
                    rt++
                    if (pp == true && rt - lt > 2) {
                        list.add(rule.substring(lt,rt))
                        break
                    }
                }

                lt = rule.indexOf(startValue,lt+1)
            }

        }

        var i = 0
        while (list.size > i){
            if (list[i].length < 3 || list[i].contains("*") || list[i].contains("^")|| list[i].contains("\\")) {
                list.removeAt(i)
                continue
            }
            i++
        }
        return list
    }
    fun getJieKey(text : String) : String{
        var vs = JIE.toString()
        vs += getTextKey(text)
        return vs
    }

    // 5 获取开始值，http://  https:// http^ || | 开头 的值，
    fun getKaishiKey(text : String) : String?{

        //  key= 小数点之前的内容

        var key = text.left(".") ?: text.left("^") ?: return null

        val v =StringBuilder()

        if (key.startsWith("||")){
            key = key.substring(2)
            v.append(HTTPX)
        }
        else{
            // 去除单管线
            if (key.startsWith("|")) key = key.substring(1)
            if (key.startsWith("http://") || key.startsWith("|http://")){
                key = key.substring(7)
                v.append(HTTP)
            }
            else if (key.startsWith("https://") || key.startsWith("|https://")){
                key = key.substring(8)
                v.append(HTTPS)
            }
            else {
                // 其它就不支持
                return null
            }
        }

        // 小于两个值或含有通配符，不管
        if (key.length < 2 || key.contains("*") || key.contains("^")) return null

        v.append(getTextKey(key))

        return v.toString()
    }

    // 6 左斜线后连续5个字符 /([0-9a-z-_]|\.){5}
    fun getZuoXieXian(text: String) : String?{
        val r = "/([0-9a-z-_]|\\.){5}"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        if (matcher.find()){
            return matcher.group()
        }

        return null
    }
    fun getZuoXieXians(text : String) : MutableList<String>{
        val r = "/([0-9a-z-_]|\\.){5}"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        val ls = ArrayList<String>()
        while (matcher.find()){
            ls.add(matcher.group())
        }

        return ls
    }
    fun getZuoXieXianKey(text : String) : String{
        var vs = ZUOXIEXIAN.toString()
        vs += getTextKey(text)
        return vs
    }

    // 7 右斜线后连续5个字符 "([0-9a-z]|\\.){5}/"
    fun getYouXieXian(text: String) : String?{
        val r = "([0-9a-z-_]|\\.){5}/"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        if (matcher.find()){
            return matcher.group()
        }

        return null
    }
    fun getYouXieXians(text : String) : MutableList<String>{
        val r = "([0-9a-z-_]|\\.){5}/"
        val matcher = Pattern
            .compile(r,Pattern.CASE_INSENSITIVE)
            .matcher(text)

        val ls = ArrayList<String>()
        while(matcher.find()){
            ls.add(matcher.group())
        }

        return ls
    }
    fun getYouXieXianKey(text : String) : String{
        var vs = YOUXIEXIAN.toString()
        vs += getTextKey(text)
        return vs
    }

    // 一段文字Key
    fun getTextKey(word : String) : String{
        with(StringBuilder()){
            // 1. 长度 +1
            append(getLengthSign(word))

            // 2 正1
            append(getWordSign(word.substring(word.length - 1)))

            // 3 倒1
            append(getWordSign(word.substring(word.length - 2,word.length - 1)))

            // 4 中间
            val mid = word.length / 2
            append(getWordSign(word.substring(mid,mid+1)))

            // 5 中间-1
            if (mid == 0) append(getWordSign(word.substring(mid,mid+1)))
            else append(getWordSign(word.substring(mid-1,mid)))

            // 6 中间+1
            if (mid == word.length - 1) append(getWordSign(word.substring(word.length - 2,word.length - 1)))
            else append(getWordSign(word.substring(mid+1,mid+2)))

            return toString()
        }
    }

    // 长度标识
    private fun getLengthSign(string:String) : String{
        val let = string.length
        if (let < 10){
            return "0" + let.toString()
        }else if (let > 99) {
            return "99"
        }else{
            return let.toString()
        }
    }

    // 字标识
    private fun getWordSign(word : String) : String{
        when(word){
            "0","1","2","3","4","5","7","8","9" -> return "0" + word
            "a" -> return "10"
            "b" -> return "11"
            "c" -> return "12"
            "d" -> return "13"
            "e" -> return "14"
            "f" -> return "15"
            "g" -> return "16"
            "h" -> return "17"
            "i" -> return "18"
            "j" -> return "19"
            "k" -> return "20"
            "l" -> return "21"
            "m" -> return "22"
            "n" -> return "23"
            "o" -> return "24"
            "p" -> return "25"
            "q" -> return "26"
            "r" -> return "27"
            "s" -> return "28"
            "t" -> return "29"
            "u" -> return "30"
            "v" -> return "31"
            "w" -> return "32"
            "x" -> return "33"
            "y" -> return "34"
            "z" -> return "35"
            "+" -> return "36"
            "-" -> return "37"
            ":" -> return "38"
            "!" -> return "39"
            "&" -> return "40"
            "_" -> return "41"
            "=" -> return "42"
            else -> return "43"
        }
    }


    // 进阶类型集
    const  val TYPE_S_SCRIPT = "1" // script 针对脚本
    const  val TYPE_S_SCRIPT_F = "2" // ~script 针对非脚本
    const  val TYPE_S_IMAGE = "3" // image 针对图片  gif  png  ico jpg  jpeg
    const  val TYPE_S_IMAGE_F = "4" // ~image 针对非图片
    const  val TYPE_S_STYLESHEET = "5" // stylesheet 针对CSS
    const  val TYPE_S_STYLESHEET_F = "6" // ~stylesheet 针对非CSS
    const  val TYPE_S_XMLHTTPREQUEST = "7" // xmlhttprequest  针对仅 XMLHTTP 请求拦截
    const  val TYPE_S_XMLHTTPREQUEST_F = "8" //
    const val TYPE_S_OBJECT = "9" // object 针对 .flash  java 等文件
    const val TYPE_S_OBJECT_F = "A" // ~object
    const val TYPE_S_SUBDOCUMENT = "B" // 内部框架请求
    const val TYPE_S_SUBDOCUMENT_F = "C" // 用不到 不加入
    const val TYPE_S_MEDIA = "D" // media 视频
    const val TYPE_S_MEDIA_F = "E" // ~medi
    const val TYPE_S_THIRD = "F" // third-party 仅匹配第三方主机
    const val TYPE_S_THIRD_F = "G" // ~third-party  反仅匹配第三方主机 即 仅匹配当前主机


    const val 黑名单地址 = 0
    const val 白名单地址 = 1 // 白名单连接
    const val 隐藏元素 = 2 // 隐藏元素
    const val 白名单元素 = 3 // 白名单元素

}